#ifndef LIBRARY_H
#define LIBRARY_H

#include <QtCore>

#define Q_ASSERT_FORCE(cond) ((!(cond)) ? qt_assert(#cond,__FILE__,__LINE__) : qt_noop())

#include "annotation.h"
#include "rendercachekey.h"

class LibraryDoc
{
public:
	LibraryDoc(QByteArray hash = QByteArray());
	LibraryDoc(const LibraryDoc &other);

	LibraryDoc &operator=(const LibraryDoc &other);

	bool isNull();

	QByteArray getHash() const;
	QString getValue(QString key) const;
	void setValue(QString key, QString value);

	QList<TextNoteAnnotation> getTextNoteAnnotations() const;
	TextNoteAnnotation addTextNoteAnnotation(int pageNumber, QPointF pos, QColor color);
	void deleteTextNoteAnnotation(int id);
	void changeTextNoteAnnotationTitle(int id, QString title);
	void changeTextNoteAnnotationText(int id, QString text);
	void changeTextNoteAnnotationColor(int id, QColor color);
	void changeTextNoteAnnotationPos(int id, QPointF pos);
	void changeTextNoteAnnotationMaximized(int id, bool maximized);
	void changeTextNoteAnnotationMaximumSize(int id, QSize maximumSize);
	QString getReportText();
	void changeReportText(QString text);
	void setViewOffset(qreal offsetNormalized);
	qreal getViewOffset();
	QHash<QString, QString> getMetadata();
	QString getFullText();
	void setFullText(QString fullText);

	QHash<int, QList<HighlightAnnotation> > getHighlights() const;
	HighlightAnnotation createHighlight(int pageNumber, QRectF box, QColor color);
	void deleteHighlight(int pageNumber, QRectF box);

protected:
	QByteArray sha1;
	QHash<QString, QString> metadata;
	// id -> annotation
	QHash<int, TextNoteAnnotation> textNoteAnnotations;
	// page number -> list of highlights
	QHash<int, QList<HighlightAnnotation> > highlights;
	QString reportText;
	qreal viewOffsetNormalized; // 0-1
	QString fullText;
	QHash<RenderCacheKey, QPair<QImage, qint64> > pageCache;
	bool pageCacheDirty;
	// WARNING
	// update the copy contrusctor when adding more members

	friend QDataStream& operator<<(QDataStream& s, const LibraryDoc& d);
	friend QDataStream& operator>>(QDataStream& s, LibraryDoc& d);
	friend QDebug operator<<(QDebug dbg, const LibraryDoc &d);
	friend class Library;
};

QDebug operator<<(QDebug dbg, const LibraryDoc &d);

class LibrarySearchResult
{
public:
	QString displayText;
	qreal score;
	LibraryDoc doc;
};

QDebug operator<<(QDebug dbg, const LibrarySearchResult &r);

class Library : public QObject
{
	Q_OBJECT

public:
	explicit Library(QString path, bool autoGit, QObject *parent = 0);
	~Library();

	bool init(QString &message, bool &fatal, bool &errors);
	bool destroy(QString &message);

	bool load();
	bool save();
	void cleanupOldBackups();

	const QHash<QByteArray, LibraryDoc> getDocs();
	const QString getPath();
	const QString getLibFileName();
	const QString getDocFileName(QByteArray docHash);
	const QString getDownloadsPath();
	const QString getDeletedPath();
	const QString getMetadataBackupPath();

	bool addFile(LibraryDoc doc);
	bool deleteFile(QByteArray docHash);
	QString getFileData(QByteArray docHash, QString key);
	void setFileData(QByteArray docHash, QString key, QString value);

	QList<TextNoteAnnotation> getTextNoteAnnotations(QByteArray docHash);
	TextNoteAnnotation addTextNoteAnnotation(QByteArray docHash, int pageNumber, QPointF pos, QColor color);
	void deleteTextNoteAnnotation(QByteArray docHash, int id);
	void changeTextNoteAnnotationTitle(QByteArray docHash, int id, QString title);
	void changeTextNoteAnnotationText(QByteArray docHash, int id, QString text);
	void changeTextNoteAnnotationColor(QByteArray docHash, int id, QColor color);
	void changeTextNoteAnnotationPos(QByteArray docHash, int id, QPointF pos);
	void changeTextNoteAnnotationMaximized(QByteArray docHash, int id, bool maximized);
	void changeTextNoteMaximumSize(QByteArray docHash, int id, QSize maximumSize);
	QString getReportText(QByteArray docHash);
	void changeReportText(QByteArray docHash, QString text);
	void setViewOffset(QByteArray docHash, qreal offsetNormalized);
	qreal getViewOffset(QByteArray docHash);
	QHash<RenderCacheKey, QPair<QImage, qint64> > getPageCache(QByteArray docHash);
	void setPageCacheDirty(QByteArray docHash);
	void setPageCache(QByteArray docHash, QHash<RenderCacheKey, QPair<QImage, qint64> > pageCache);
	void loadPageCache(QByteArray docHash);
	void savePageCache(QByteArray docHash);

	QHash<int, QList<HighlightAnnotation> > getHighlights(QByteArray docHash);
	HighlightAnnotation createHighlight(QByteArray docHash, int pageNumber, QRectF box, QColor color);
	void deleteHighlight(QByteArray docHash, int pageNumber, QRectF box);

	QList<LibrarySearchResult> search(QString query);

	void setOpen(QByteArray docHash);
	void setClosed(QByteArray docHash);
	QList<QByteArray> getOpenDocs();

	bool setAutoGit(bool autoGit, QString &message);
	bool getAutoGit();
	bool detectGit();
	bool gitPull(QString &message);
	bool isGitRepoClean(QString &message);
	bool gitCommitAndPush(QString &message);

signals:

protected:
	QString path;
	QHash<QByteArray, LibraryDoc> docs;
	QList<QByteArray> openDocs;
	bool autoGit;

	friend QDataStream& operator<<(QDataStream& s, const Library& l);
	friend QDataStream& operator>>(QDataStream& s, Library& l);
};

QString keyFromEndNoteKey(QString key);
QHash<QString, QString> metadataFromEndNote(QString metadata);

QDataStream& operator<<(QDataStream& s, const LibraryDoc& d);
QDataStream& operator>>(QDataStream& s, LibraryDoc& d);

QDataStream& operator<<(QDataStream& s, const Library& l);
QDataStream& operator>>(QDataStream& s, Library& l);

#endif // LIBRARY_H
